package red;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import javax.swing.Timer;

import logica.mensajes.Mensaje;
import logica.mensajes.MensajeDatos;
import logica.mensajes.MensajeFinC;
import logica.mensajes.MensajeIniC;
import logica.mensajes.MensajePing;
import logica.mensajes.MensajePong;
import logica.mensajes.MensajeTexto;

public class ServerKeepAliveSocket {
	private Socket 		   sock;
	private SocketListener sl    = null;
	private boolean 	   ka_on;
	private Timer 		   timer;
	
	// Para la transmision de datos
	private DataInputStream in;
	private DataOutputStream out;
	
	// El emmarcador
	private Enmarcador marker;
	// El ConectionManager
	private ConectionManager manager; 
	
	// Leer de la configuracion
	//private int id_cap = 1; (este cap)
	// Necesito un generador de nros 
	// private int id_msj = 1;	 
	private int id_org;
	
	public ServerKeepAliveSocket(Socket s, ConectionManager cm){
		sock = s;
		manager = cm;
		ka_on = false;
		
		try {
			in     = new DataInputStream(sock.getInputStream());
			out    = new DataOutputStream(sock.getOutputStream());
			marker = new Enmarcador(in, out);
			
			// default: 60 seg de timer
			timer  = new Timer(5 * 1000, new ActiveKeepAliveListener());
			timer.setRepeats(true);
			
			new receptor(this).start();
	
		} catch (IOException e) { e.printStackTrace(); }		
	}
	
	public void setKeepAlive(boolean ka){
		ka_on = ka;
		if(ka) { // ka == false
			timer.start();
		} else {
			timer.stop();
		}
	}
	
	public boolean getKeepAlive(){
		return ka_on;
	}
	
	private void desconectar(){
		try {
			manager.remover(id_org);
			timer.stop();
			in.close();
			out.close();
			sock.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public synchronized void send(Mensaje m) throws IOException{
		byte[] msj_byte = m.toByte(); 
		marker.enmarcar(msj_byte);
	}
	
	public void addListener(SocketListener sl){
		this.sl = sl;
	}

	private String getTipo(byte[] input) throws IOException{
		String ret = null;
		ByteArrayInputStream bais = new ByteArrayInputStream(input);
		DataInputStream in  = new DataInputStream(bais);
		in.readUTF();
		ret = in.readUTF(); 		
		in.close();
		bais.close();
		
		return ret;
	}
	
	private class receptor extends Thread{
		
		ServerKeepAliveSocket papa;
		
		public receptor(ServerKeepAliveSocket papa){
			this.papa = papa;
		}
		
		public void run() {		
			String tipo = null;
			try {
				
				byte[] req;
				while ((req = marker.desenmarcar()) != null) {
					System.out.println("Llego un mensje de: " + req.length + " bytes");
					tipo = getTipo(req);
					
					if(tipo.equals("DATO")){
						MensajeDatos mdc = MensajeDatos.fromByte(req);
						sl.agregar_mensaje(mdc);						
					} 
					else if(tipo.equals("INIC")){
						MensajeIniC m = MensajeIniC.fromByte(req);
						id_org = m.getIDorigen(); 
							
						if(!manager.existe(id_org)){
							manager.registrar(id_org, this.papa);
						} 
					}
					
					else if(tipo.equals("TXTO")){
						MensajeTexto mtexto = MensajeTexto.fromByte(req);
						System.out.println("Recibi un mensaje de texto, viene del hospital?");
					}
					else if(tipo.equals("PING")){
						MensajePing mping = MensajePing.fromByte(req);
						System.out.println("Recibi PING");
						
						MensajePong m = new MensajePong();
						m.setIDmensaje(1); // Usar datos de mping para validar?
						m.setIDorigen(1);
						
						send(m);				
					}
					else if(tipo.equals("PONG")){
						MensajePong mpong = MensajePong.fromByte(req);		
						System.out.println("Recibi pong, la conexion esta viva =)");
					}
					
					else if(tipo.equals("FINC")){
						MensajeFinC mfinc = MensajeFinC.fromByte(req);
						
						
						break;
					}
					
				} // Fin while
				
			} catch (IOException ioe) {
				System.out.println("El cliente se desconecto");
				System.err.println("Error handling client: " + ioe.getMessage());
			} catch (MsjNotForMeException e) {
				e.printStackTrace();
			} finally {
				System.out.println("Comunicacion terminada");
				desconectar();
			}
			
		}
			
	}
	
	
	private class ActiveKeepAliveListener implements ActionListener{
		public void actionPerformed(ActionEvent arg0) {
			try {
				send(new MensajePing());
				System.out.println("Ping enviado");
			} catch (IOException e) {
				System.err.println("Se perdio la comunicacion con la Chacra");
				desconectar();
			}			
		}
	}
	
}

